<template>
  <view
    v-if="show"
    :id="$sUid"
    class="s-notice-bar"
    :class="c_class"
    :style="c_style"
    @click="onClick"
  >
    <slot name="leftIcon">
      <s-icon
        v-if="leftIcon"
        :name="leftIcon"
        custom-class="s-notice-bar__left-icon"
        :custom-style="leftIconStyle"
      />
    </slot>
    <view class="s-notice-bar__wrap">
      <view
        class="s-notice-bar__content"
        :class="content_class"
        :animation="animationData"
      >
        <slot>
          <swiper
            v-if="vertical"
            class="s-notice-bar__swiper"
            vertical
            :autoplay="list.length > 0"
            circular
            disable-touch
            :interval="interval"
          >
            <swiper-item
              v-for="(item, index) of list"
              :key="index"
              class="s-notice-bar__swiper-item"
            >
              <view
                class="s-notice-bar__swiper-item__text"
                :class="swiper_item_text_class"
              >
                {{ item }}
              </view>
            </swiper-item>
          </swiper>
          <text v-else-if="text">{{ text }}</text>
        </slot>
      </view>
    </view>
    <slot name="rightIcon">
      <s-icon
        v-if="mode === 'close'"
        name="cross"
        custom-class="s-notice-bar__right-icon"
        :custom-style="rightIconStyle"
        @click="onCloseClick"
      />
      <s-icon
        v-else-if="mode === 'link'"
        name="arrow"
        custom-class="s-notice-bar__right-icon"
        :custom-style="rightIconStyle"
      />
      <s-icon
        v-else-if="rightIcon"
        :name="rightIcon"
        custom-class="s-notice-bar__right-icon"
        :custom-style="rightIconStyle"
      />
    </slot>
  </view>
</template>

<script>
import componentMixin from '../../mixins/componentMixin';

/**
 * s-notice-bar 通知栏
 * @description 用于循环播放展示一组消息通知。
 * @property {Number|String} height 通知栏高度
 * @property {String} mode = [close|link] 通知栏模式，可选值为 close | link
 * @property {String} text 通知文本内容
 * @property {String} background 通知栏背景
 * @property {String} color 文本颜色
 * @property {Number} delay 横向动画延迟时间(s)
 * @property {Number} speed 横向滚动速率 (px/s)
 * @property {Boolean} scrollable 是否开启滚动播放，内容长度溢出时默认开启
 * @property {Boolean} wrapable 是否开启文本换行，横向只在禁用滚动时生效
 * @property {Boolean} vertical 是否开启垂直滚动
 * @property {Array<String>} list 垂直文本数组
 * @property {Number} interval 垂直切换时间间隔(ms)
 * @property {String} leftIcon 左侧图标名称或图片链接，等同于 Icon 组件的 name 属性
 * @property {String} rightIcon 右侧图标名称或图片链接，等同于 Icon 组件的 name 属性
 * @property {String|Object} leftIconStyle 左侧图标样式
 * @property {String|Object} rightIconStyle 右侧图标样式
 * @event {Function} click (e) 点击事件
 * @event {Function} close (e) 关闭事件
 * @example <s-notice-bar text="" />
 */
export default {
  name: 'SNoticeBar',
  mixins: [componentMixin],
  props: {
    height: [Number, String],
    mode: String,
    text: String,
    background: String,
    color: String,
    delay: {
      type: Number,
      default: 1,
    },
    speed: {
      type: Number,
      default: 60,
    },
    scrollable: {
      type: Boolean,
      default: null,
    },
    wrapable: Boolean,
    vertical: Boolean,
    list: {
      type: Array,
      default: () => [],
    },
    interval: {
      type: Number,
      default: 5000,
    },
    leftIcon: String,
    rightIcon: String,
    leftIconStyle: [String, Object],
    rightIconStyle: [String, Object],
  },
  data: () => ({
    show: true,
    animationData: {},
  }),
  computed: {
    c_class() {
      return this.$mergeClass({
        's-notice-bar--vertical': this.vertical,
        's-notice-bar--wrapable': this.wrapable,
      }, this.custom_class);
    },
    c_style() {
      return this.$mergeStyle({
        height: this.$addUnit(this.height),
        background: this.background,
        color: this.color,
      }, this.custom_style);
    },
    content_class() {
      return this.$mergeClass({
        's-ellipsis': this.scrollable === false && !this.wrapable,
      });
    },
    swiper_item_text_class() {
      return this.$mergeClass({
        's-ellipsis': !this.wrapable,
      });
    },
  },
  watch: {
    text() {
      this.init();
    },
  },
  created() {
    Object.assign(this, {
      resetAnimation: uni.createAnimation({
        duration: 0,
        timingFunction: 'linear',
      }),
      wrapWidth: 0,
      contentWidth: 0,
      duration: 0,
      animation: null,
      timer: null,
    });
  },
  mounted() {
    this.init();
  },
  beforeDestroy() {
    this.clearTimer();
  },
  methods: {
    init() {
      this.clearTimer();
      if (this.vertical) return;
      this.timer = setTimeout(() => {
        Promise.all([
          this.$getRect(`#${this.$sUid} .s-notice-bar__wrap`),
          this.$getRect(`#${this.$sUid} .s-notice-bar__content`),
        ]).then(rects => {
          const [wrapRect, contentRect] = rects;
          const { speed, scrollable, delay } = this;
          if (
            !wrapRect ||
            !contentRect ||
            !contentRect.width ||
            !wrapRect.width ||
            scrollable === false
          ) {
            return;
          }
          if (scrollable || wrapRect.width < contentRect.width) {
            const duration = ((wrapRect.width + contentRect.width) / speed) * 1000;
            this.wrapWidth = wrapRect.width;
            this.contentWidth = contentRect.width;
            this.duration = duration;
            this.animation = uni.createAnimation({
              duration,
              timingFunction: 'linear',
              delay,
            });
            this.scroll(true);
          }
        });
      }, 1000 / 30);
    },
    scroll(isInit = false) {
      this.clearTimer();

      this.animationData = this.resetAnimation
        .translateX(isInit ? 0 : this.wrapWidth)
        .step()
        .export();

      this.timer = setTimeout(() => {
        this.animationData = this.animation
          .translateX(-this.contentWidth)
          .step()
          .export();
        this.timer = setTimeout(this.scroll, this.duration);
      }, 1000 / 30);
    },
    clearTimer() {
      if (this.timer) {
        clearTimeout(this.timer);
        this.timer = null;
      }
    },
    onCloseClick(e) {
      if (this.mode === 'close') {
        this.clearTimer();
        this.show = false;
        this.$emit('close', e);
      }
    },
    onClick(e) {
      this.$emit('click', e);
    },
  },
};
</script>

<style lang="scss" src="./index.scss"></style>
